home *** CD-ROM | disk | FTP | other *** search
- /*------------------------------------------------------------------------------
- #
- # Apple Macintosh Developer Technical Support
- #
- # MultiFinder-Aware Simple Sample Application
- #
- # Sample
- #
- # SampleInit.c - C Source (Init Segment)
- #
- # Copyright © 1989 Apple Computer, Inc.
- # All rights reserved.
- #
- # Versions:
- # 1.00 08/88
- # 1.01 11/88
- # 1.02 04/89
- # 1.03 06/89
- # 1.04 06/92
- #
- # Components:
- # Sample.p June 1, 1989
- # Sample.c June 1, 1989
- # SampleInit.c June 2, 1992
- # Sample.a June 1, 1989
- # Sample.inc1.a June 1, 1989
- # SampleMisc.a June 1, 1989
- # Sample.r June 1, 1989
- # Sample.h June 1, 1989
- # PSample.make June 1, 1989
- # CSample.make June 1, 1989
- # ASample.make June 1, 1989
- # CSample.π June 2, 1992
- # CSample.π.rsrc June 2, 1992
- #
- # Sample is an example application that demonstrates how to
- # initialize the commonly used toolbox managers, operate
- # successfully under MultiFinder, handle desk accessories,
- # and create, grow, and zoom windows.
- #
- # It does not by any means demonstrate all the techniques
- # you need for a large application. In particular, Sample
- # does not cover exception handling, multiple windows/documents,
- # sophisticated memory management, printing, or undo. All of
- # these are vital parts of a normal full-sized application.
- #
- # This application is an example of the form of a Macintosh
- # application; it is NOT a template. It is NOT intended to be
- # used as a foundation for the next world-class, best-selling,
- # 600K application. A stick figure drawing of the human body may
- # be a good example of the form for a painting, but that does not
- # mean it should be used as the basis for the next Mona Lisa.
- #
- # We recommend that you review this program or TESample before
- # beginning a new application.
- #
- ------------------------------------------------------------------------------*/
-
-
- /* Segmentation strategy:
-
- This program consists of three segments.
- 1. "Main" contains most of the code, including the MPW libraries, and the
- main program. This segment is in the file Sample.c
- 2. "Initialize" contains code that is only used once, during startup, and
- can be unloaded after the program starts. This segment is in the file
- SampleInit.c.
- 3. "%A5Init" is automatically created by the Linker to initialize globals
- for the MPW libraries and is unloaded right away. */
-
-
- /* SetPort strategy:
-
- Toolbox routines do not change the current port. In spite of this, in this
- program we use a strategy of calling SetPort whenever we want to draw or
- make calls which depend on the current port. This makes us less vulnerable
- to bugs in other software which might alter the current port (such as the
- bug (feature?) in many desk accessories which change the port on OpenDeskAcc).
- Hopefully, this also makes the routines from this program more self-contained,
- since they don't depend on the current port setting. */
-
- #include <OSUtils.h>
- #include <Traps.h>
- #include "Sample.h" /* bring in all the #defines for Sample */
-
- /* The "g" prefix is used to emphasize that a variable is global. */
- /* All are extern since the variables are declared in the main segment. */
-
- /* GMac is used to hold the result of a SysEnvirons call. This makes
- it convenient for any routine to check the environment. */
- extern SysEnvRec gMac; /* set up by Initialize */
-
- /* GHasWaitNextEvent is set at startup, and tells whether the WaitNextEvent
- trap is available. If it is false, we know that we must call GetNextEvent. */
- extern Boolean gHasWaitNextEvent; /* set up by Initialize */
-
- /* GInBackground is maintained by our osEvent handling routines. Any part of
- the program can check it to find out if it is currently in the background. */
- extern Boolean gInBackground; /* maintained by Initialize and DoEvent */
-
-
- /* The following globals are the state of the window. If we supported more than
- one window, they would be attatched to each document, rather than globals. */
-
- /* GStopped tells whether the stop light is currently on stop or go. */
- extern Boolean gStopped; /* maintained by Initialize and SetLight */
-
- /* GStopRect and gGoRect are the rectangles of the two stop lights in the window. */
- extern Rect gStopRect; /* set up by Initialize */
- extern Rect gGoRect; /* set up by Initialize */
-
-
- /* Set up the whole world, including global variables, Toolbox managers,
- and menus. We also create our one application window at this time.
- Since window storage is non-relocateable, how and when to allocate space
- for windows is very important so that heap fragmentation does not occur.
- Because Sample has only one window and it is only disposed when the application
- quits, we will allocate its space here, before anything that might be a locked
- relocatable object gets into the heap. This way, we can force the storage to be
- in the lowest memory available in the heap. Window storage can differ widely
- amongst applications depending on how many windows are created and disposed. */
-
- /* 1.01 - The code that used to be part of ForceEnvirons has been moved into
- this module. If an error is detected, instead of merely doing an ExitToShell,
- which leaves the user without much to go on, we call AlertUser, which puts
- up a simple alert that just says an error occurred and then calls ExitToShell.
- Since there is no other cleanup needed at this point if an error is detected,
- this form of error- handling is acceptable. If more sophisticated error recovery
- is needed, an exception mechanism, such as is provided by Signals, can be used. */
-
- void Initialize()
- {
- Handle menuBar;
- DialogPtr newDialogP;
- long total, contig;
- EventRecord event;
- short count;
-
- gInBackground = false;
-
- InitGraf((Ptr) &qd.thePort);
- InitFonts();
- InitWindows();
- InitMenus();
- TEInit();
- InitDialogs(nil);
- InitCursor();
-
- /* Call MPPOpen and ATPLoad at this point to initialize AppleTalk,
- if you are using it. */
- /* NOTE -- It is no longer necessary, and actually unhealthy, to check
- PortBUse and SPConfig before opening AppleTalk. The drivers are capable
- of checking for port availability themselves. */
-
- /* This next bit of code is necessary to allow the default button of our
- alert be outlined.
- 1.02 - Changed to call EventAvail so that we don't lose some important
- events. */
-
- for (count = 1; count <= 3; count++)
- EventAvail(everyEvent, &event);
-
- /* Ignore the error returned from SysEnvirons; even if an error occurred,
- the SysEnvirons glue will fill in the SysEnvRec. You can save a redundant
- call to SysEnvirons by calling it after initializing AppleTalk. */
-
- SysEnvirons(kSysEnvironsVersion, &gMac);
-
- /* Make sure that the machine has at least 128K ROMs. If it doesn't, exit. */
-
- if (gMac.machineType < 0) AlertUser();
-
- /* 1.02 - Move TrapAvailable call to after SysEnvirons so that we can tell
- in TrapAvailable if a tool trap value is out of range. */
-
- gHasWaitNextEvent = TrapAvailable(_WaitNextEvent, ToolTrap);
-
- /* 1.01 - We used to make a check for memory at this point by examining ApplLimit,
- ApplicZone, and StackSpace and comparing that to the minimum size we told
- MultiFinder we needed. This did not work well because it assumed too much about
- the relationship between what we asked MultiFinder for and what we would actually
- get back, as well as how to measure it. Instead, we will use an alternate
- method comprised of two steps. */
-
- /* It is better to first check the size of the application heap against a value
- that you have determined is the smallest heap the application can reasonably
- work in. This number should be derived by examining the size of the heap that
- is actually provided by MultiFinder when the minimum size requested is used.
- The derivation of the minimum size requested from MultiFinder is described
- in Sample.h. The check should be made because the preferred size can end up
- being set smaller than the minimum size by the user. This extra check acts to
- insure that your application is starting from a solid memory foundation. */
-
- if ((long) GetApplLimit() - (long) ApplicationZone() < kMinHeap) AlertUser();
-
- /* Next, make sure that enough memory is free for your application to run. It
- is possible for a situation to arise where the heap may have been of required
- size, but a large scrap was loaded which left too little memory. To check for
- this, call PurgeSpace and compare the result with a value that you have determined
- is the minimum amount of free memory your application needs at initialization.
- This number can be derived several different ways. One way that is fairly
- straightforward is to run the application in the minimum size configuration
- as described previously. Call PurgeSpace at initialization and examine the value
- returned. However, you should make sure that this result is not being modified
- by the scrap's presence. You can do that by calling ZeroScrap before calling
- PurgeSpace. Make sure to remove that call before shipping, though. */
-
- /* ZeroScrap(); */
-
- PurgeSpace(&total, &contig);
- if (total < kMinSpace) AlertUser();
-
- /* The extra benefit to waiting until after the Toolbox Managers have been initialized
- to check memory is that we can now give the user an alert to tell him/her what
- happened. Although it is possible that the memory situation could be worsened by
- displaying an alert, MultiFinder would gracefully exit the application with
- an informative alert if memory became critical. Here we are acting more
- in a preventative manner to avoid future disaster from low-memory problems. */
-
- newDialogP = GetNewDialog(rWindow, nil, (WindowPtr) -1);
- if ( newDialogP == nil ) AlertUser();
- SetPort(newDialogP);
- TextFont(geneva);
- TextSize(9);
- TextFace(normal);
-
- menuBar = GetNewMBar(rMenuBar); /* read menus into menu bar */
- if ( menuBar == nil ) AlertUser();
- SetMenuBar(menuBar); /* install menus */
- DisposeHandle(menuBar);
- AppendResMenu(GetMenuHandle(mApple), 'DRVR'); /* add DA names to Apple menu */
- DrawMenuBar();
-
- gStopped = true;
- } /*Initialize*/
-
-
-
- /* Check to see if a given trap is implemented. This is only used by the
- Initialize routine in this program, so we put it in the Initialize segment.
- The recommended approach to see if a trap is implemented is to see if
- the address of the trap routine is the same as the address of the
- Unimplemented trap. */
- /* 1.02 - Needs to be called after call to SysEnvirons so that it can check
- if a ToolTrap is out of range of a pre-MacII ROM. */
-
- Boolean TrapAvailable(short tNumber, TrapType tType)
- {
- if ( ( tType == ToolTrap ) &&
- ( gMac.machineType > envMachUnknown ) &&
- ( gMac.machineType < envMacII ) ) { /* it's a 512KE, Plus, or SE */
- tNumber = tNumber & 0x03FF;
- if ( tNumber > 0x01FF ) /* which means the tool traps */
- tNumber = _Unimplemented; /* only go to 0x01FF */
- }
- return NGetTrapAddress(tNumber, tType) != GetOSTrapAddress(_Unimplemented);
- } /*TrapAvailable*/